// Kony


#include "AbilitySystem/Abilitys/ProjectileSpeellGameplayAbility.h"

#include "AbilitySystemBlueprintLibrary.h"
#include "AbilitySystemComponent.h"
#include "Actor/BaseProjectile.h"
#include "Interaction/CombatInterface.h"
#include "Kismet/KismetSystemLibrary.h"
#include "GASC_HuanLing/Public/BaseGameplayTags.h"


/**
 * 激活该投射物技能能力（Gameplay Ability System 自动调用）
 *
 * @param Handle             能力的句柄，用于唯一标识该技能实例
 * @param ActorInfo          与能力相关的角色信息（包括控制器、角色、AbilitySystemComponent等）
 * @param ActivationInfo     激活相关信息（如是手动触发还是通过事件）
 * @param TriggerEventData   触发此能力的事件数据（如由 GameplayEvent 触发）
 */
void UProjectileSpeellGameplayAbility::ActivateAbility(const FGameplayAbilitySpecHandle Handle,
	const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo,
	const FGameplayEventData* TriggerEventData)
{
	Super::ActivateAbility(Handle, ActorInfo, ActivationInfo, TriggerEventData);
	// const bool bIsServer = HasAuthority(&ActivationInfo);
	//打印日志
	// UKismetSystemLibrary::PrintString(this, FString("ActivateAbility(C++)"),true,true, FLinearColor::Yellow,3);
}

void UProjectileSpeellGameplayAbility::SpawnProjectile(const FVector& ProjectileTargetLocation, const FGameplayTag& SocketTag, bool bOverridePitch, float PitchOverride, AActor* HomingTarget)
{
	//判断是否是处于服务器
	const bool bIsServer = GetAvatarActorFromActorInfo()->HasAuthority();
	if (!bIsServer) return;
	//战斗接口
	ICombatInterface* CombatInterface = Cast<ICombatInterface>(GetAvatarActorFromActorInfo());
	if (CombatInterface)
	{
		//从接口中获取到 玩家角色设定的武器插槽位置
		// const FVector SocketLocation = CombatInterface->GetCombatSocketLocation(); 这是旧版，新版是执行版本 因为改成了蓝图可调用
		//FBaseGameplayTags::Get().CombatSocket_Weapon 之前默认为武器插槽
		const FVector SocketLocation = ICombatInterface::Execute_GetCombatSocketLocation(
			GetAvatarActorFromActorInfo(),
			SocketTag,false,150.0f);
		
		//计算投射物发射方向
		FRotator Rotation = (ProjectileTargetLocation - SocketLocation).Rotation();
		//如果需要，可以在蓝图中设置投射物发射方向 调整俯仰角值
		if (bOverridePitch)
		{
			Rotation.Pitch = PitchOverride;
		}
		/************** Spawn Projectile (延迟生成投射物) **************
		 * 使用 SpawnActorDeferred 生成投射物实例，并延迟初始化参数
		 * 
		 * 参数说明：
		 * - ProjectileClass：要生成的投射物类（继承自 ABaseProjectile）
		 * - SpawnTransform：生成位置、方向（一般来自武器Socket或摄像头）
		 * - GetOwningActorFromActorInfo()：技能所属的Actor，用于设定Owner
		 * - Cast<APawn>(...)：设置Instigator（攻击归属者），一般是Pawn角色
		 * - AlwaysSpawn：无论是否有碰撞都强制生成
		 ***************************************************************/
		FTransform SpawnTransform;
		SpawnTransform.SetLocation(SocketLocation);
		//设置投射物方向旋转 这样就可以让投射物向目标飞行
		SpawnTransform.SetRotation(Rotation.Quaternion());
		
		ABaseProjectile* Projectile = GetWorld()->SpawnActorDeferred<ABaseProjectile>(
			ProjectileClass,
			SpawnTransform,
			GetOwningActorFromActorInfo(),
			Cast<APawn>(GetOwningActorFromActorInfo()),
			ESpawnActorCollisionHandlingMethod::AlwaysSpawn);
		//设置伤害效果参数,这里目标演员暂时不知道是谁 所以默认空值
		Projectile->DamageEffectParams =  MakeDamageEffectParamsFromClassDefaults();
		//完成生成过程
		Projectile->FinishSpawning(SpawnTransform);
	}
}

//当前技能描述
FString UProjectileSpeellGameplayAbility::GetDescription(int32 Level, const FText& Title, const FText& Description)
{
	// const float Damage = GetDamageByDamageType(Level,FBaseGameplayTags::Get().Damage_Fire);
	const float ScaledDamage = Damage.GetValueAtLevel(Level);
	const float ManaCost = FMath::Abs(GetManaCost(Level));
	const float Cooldown = GetCooldown(Level);
	FString FormattedDescription;
	if (!Description.IsEmpty())
	{
		// 优先从数据资产模板生成描述
		TArray<FStringFormatArg> Args;
		Args.Add(FStringFormatArg(FString::Printf(TEXT("%.1f"), ScaledDamage)));
		Args.Add(FStringFormatArg(FString::Printf(TEXT("%.1f"), ManaCost)));
		Args.Add(FStringFormatArg(FString::Printf(TEXT("%.1f"), Cooldown)));
		Args.Add(FStringFormatArg(Level));
		Args.Add(FStringFormatArg(FMath::Min(Level,NumProjectiles)));
		
		FormattedDescription = FString::Format(*Description.ToString(), Args);
		FormattedDescription = FormattedDescription.Replace(TEXT("\\n"), TEXT("\n"));
	}
	if (Level == 1)
	{
		return FString::Printf(TEXT(
								"<Title>%s</>\n"
								"<Small>等级: </><Level>%d</>\n"
								"<Small>法力消耗: </><ManaCost>%.1f</>\n"
								"<Small>冷却时间: </><Cooldown>%.1f</>\n\n"
								"<Default>描述:</>\n"
								"%s\n"
								),
								*Title.ToString(),
								Level,
								ManaCost,
								Cooldown,
								*FormattedDescription);
	}
	else
	{
		return FString::Printf(TEXT(
								"<Title>%s</>\n"
								"<Small>等级: </><Level>%d</>\n"
								"<Small>法力消耗: </><ManaCost>%.1f</>\n"
								"<Small>冷却时间: </><Cooldown>%.1f</>\n\n"
								"<Default>描述:</>\n"
								"%s\n"
								),
								*Title.ToString(),
								Level,
								ManaCost,
								Cooldown,
								*FormattedDescription);
	}
}
//下一级技能描述
FString UProjectileSpeellGameplayAbility::GetNextLevelDescription(int32 Level, const FText& Title, const FText& Description)
{
	// const float Damage = GetDamageByDamageType(Level,FBaseGameplayTags::Get().Damage_Fire);
	const float ScaledDamage = Damage.GetValueAtLevel(Level);
	const float ManaCost = FMath::Abs(GetManaCost(Level));
	const float Cooldown = GetCooldown(Level);

	FString FormattedDescription;
	if (!Description.IsEmpty())
	{
		// 优先从数据资产模板生成描述
		TArray<FStringFormatArg> Args;
		Args.Add(FStringFormatArg(FString::Printf(TEXT("%.1f"), ScaledDamage)));
		Args.Add(FStringFormatArg(FString::Printf(TEXT("%.1f"), ManaCost)));
		Args.Add(FStringFormatArg(FString::Printf(TEXT("%.1f"), Cooldown)));
		Args.Add(FStringFormatArg(Level));
		Args.Add(FStringFormatArg(FMath::Min(Level,NumProjectiles)));
		FormattedDescription = FString::Format(*Description.ToString(), Args);
		FormattedDescription = FormattedDescription.Replace(TEXT("\\n"), TEXT("\n"));
	}
	else
	{
		FormattedDescription = TEXT("发射投射物并造成伤害");
	}

	return FString::Printf(TEXT(
							"<Title>%s</>\n"
							"<Small>等级: </><Level>%d</>\n"
							"<Small>法力消耗: </><ManaCost>%.1f</>\n"
							"<Small>冷却时间: </><Cooldown>%.1f</>\n\n"
							"<Default>描述:</>\n"
							"%s\n"
							),
							*Title.ToString(),
							Level,
							ManaCost,
							Cooldown,
							*FormattedDescription);
	
}
